
package cartagows.wsframework.wssecurity.policy.model;

import java.util.ArrayList;
import java.util.Iterator;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import org.apache.neethi.PolicyComponent;

import cartagows.wsframework.wssecurity.policy.SP11Constants;
import cartagows.wsframework.wssecurity.policy.SP12Constants;
import cartagows.wsframework.wssecurity.policy.SPConstants;

public class SupportingToken extends AbstractSecurityAssertion implements
        AlgorithmWrapper, TokenWrapper {

    private int type;
    private AlgorithmSuite algorithmSuite;
    private ArrayList tokens = new ArrayList();
    private SignedEncryptedElements signedElements;
    private SignedEncryptedElements encryptedElements;
    private SignedEncryptedParts signedParts;
    private SignedEncryptedParts encryptedParts;

    public SupportingToken(int type, int version ) {
        this.type = type;
        setVersion(version);
    }
    
    public AlgorithmSuite getAlgorithmSuite() {
        return algorithmSuite;
    }

    public void setAlgorithmSuite(AlgorithmSuite algorithmSuite) {
        this.algorithmSuite = algorithmSuite;
    }

    public ArrayList getTokens() {
        return tokens;
    }

    public void addToken(Token token) {
        this.tokens.add(token);
    }

    public int getTokenType() {
        return type;
    }

    public void setTokenType(int type) {
        this.type = type;
    }

    public SignedEncryptedElements getEncryptedElements() {
        return encryptedElements;
    }

    public void setEncryptedElements(SignedEncryptedElements encryptedElements) {
        this.encryptedElements = encryptedElements;
    }

    public SignedEncryptedParts getEncryptedParts() {
        return encryptedParts;
    }

    public void setEncryptedParts(SignedEncryptedParts encryptedParts) {
        this.encryptedParts = encryptedParts;
    }

    public SignedEncryptedElements getSignedElements() {
        return signedElements;
    }

    public void setSignedElements(SignedEncryptedElements signedElements) {
        this.signedElements = signedElements;
    }

    public SignedEncryptedParts getSignedParts() {
        return signedParts;
    }

    public void setSignedParts(SignedEncryptedParts signedParts) {
        this.signedParts = signedParts;
    }

    public void setToken(Token tok) {
        this.addToken(tok);
    }

    public QName getName() {
        //TODO Should we refactor this class ?? with a SuppotingTokenBase and sub classes 
        switch (type) {
        case SPConstants.SUPPORTING_TOKEN_SUPPORTING:
            return version == SPConstants.SP_V12 ? SP12Constants.SUPPORTING_TOKENS : 
                                                                    SP11Constants.SUPPORTING_TOKENS;
        case SPConstants.SUPPORTING_TOKEN_SIGNED:
            return version == SPConstants.SP_V12 ? SP12Constants.SIGNED_SUPPORTING_TOKENS : 
                                                             SP11Constants.SIGNED_SUPPORTING_TOKENS;
        case SPConstants.SUPPORTING_TOKEN_ENDORSING:
            return version == SPConstants.SP_V12 ? SP12Constants.ENDORSING_SUPPORTING_TOKENS :
                                                          SP11Constants.ENDORSING_SUPPORTING_TOKENS;
        case SPConstants.SUPPORTING_TOKEN_SIGNED_ENDORSING:
            return version == SPConstants.SP_V12 ? SP12Constants.SIGNED_ENDORSING_SUPPORTING_TOKENS: 
                                                   SP11Constants.SIGNED_ENDORSING_SUPPORTING_TOKENS;
        case SPConstants.SUPPORTING_TOKEN_ENCRYPTED:
            return SP12Constants.ENCRYPTED_SUPPORTING_TOKENS;
            
        case SPConstants.SUPPORTING_TOKEN_SIGNED_ENCRYPTED:
            return SP12Constants.SIGNED_ENCRYPTED_SUPPORTING_TOKENS;
            
        case SPConstants.SUPPORTING_TOKEN_ENDORSING_ENCRYPTED:
            return SP12Constants.ENDORSING_ENCRYPTED_SUPPORTING_TOKENS;
            
        case SPConstants.SUPPORTING_TOKEN_SIGNED_ENDORSING_ENCRYPTED:
            return SP12Constants.SIGNED_ENDORSING_ENCRYPTED_SUPPORTING_TOKENS;
        default:
            return null;
        }
    }
    
    public boolean isEncryptedToken() {
        
        switch (type) {
        case SPConstants.SUPPORTING_TOKEN_SUPPORTING:
            return false;
        case SPConstants.SUPPORTING_TOKEN_SIGNED:
            return false;
        case SPConstants.SUPPORTING_TOKEN_ENDORSING:
            return false;
        case SPConstants.SUPPORTING_TOKEN_SIGNED_ENDORSING:
            return false;
        case SPConstants.SUPPORTING_TOKEN_ENCRYPTED:
            return true;        
        case SPConstants.SUPPORTING_TOKEN_SIGNED_ENCRYPTED:
            return true;         
        case SPConstants.SUPPORTING_TOKEN_ENDORSING_ENCRYPTED:
            return true;          
        case SPConstants.SUPPORTING_TOKEN_SIGNED_ENDORSING_ENCRYPTED:
            return true;
        default:
            return false;
        }
        
        
    }

    public PolicyComponent normalize() {
        return this;
    }

    public short getType() {
        return org.apache.neethi.Constants.TYPE_ASSERTION;
    }

    public void serialize(XMLStreamWriter writer) throws XMLStreamException {
        String namespaceURI = getName().getNamespaceURI();

        String prefix = writer.getPrefix(namespaceURI);
        if (prefix == null) {
            prefix = getName().getPrefix();
            writer.setPrefix(prefix, namespaceURI);
        }

        String localname = getName().getLocalPart();

        // <sp:SupportingToken>
        writer.writeStartElement(prefix, localname, namespaceURI);
        
        // xmlns:sp=".."
        writer.writeNamespace(prefix, namespaceURI);

        String pPrefix = writer.getPrefix(SPConstants.POLICY.getNamespaceURI());
        if (pPrefix == null) {
            pPrefix = SPConstants.POLICY.getPrefix();
            writer.setPrefix(pPrefix, SPConstants.POLICY.getNamespaceURI());
        }
        // <wsp:Policy>
        writer.writeStartElement(pPrefix, SPConstants.POLICY.getLocalPart(),
                SPConstants.POLICY.getNamespaceURI());

        Token token;
        for (Iterator iterator = getTokens().iterator(); iterator.hasNext();) {
            // [Token Assertion] +
            token = (Token) iterator.next();
            token.serialize(writer);
        }

        
        if (signedParts != null) {
            signedParts.serialize(writer);
            
        } else if (signedElements != null) {
            signedElements.serialize(writer);
            
        } else if (encryptedParts != null) {
            encryptedParts.serialize(writer);
            
        } else if (encryptedElements != null) {
            encryptedElements.serialize(writer);
        }
        // </wsp:Policy>
        writer.writeEndElement();

        writer.writeEndElement();
        // </sp:SupportingToken>
    }
}
